#include <cstring>
#include <iostream>
#include <list>

#include <boost/foreach.hpp>
#include <boost/function.hpp>
#include <boost/thread.hpp>

#include <Common/Debug.hh>
#include <Common/Logging.hh>
#include <Common/AutoSingleton.hh>
#include <Common/Future.hh>

// ----------------------------------------------------------------------------

class TaskError
{
	public: // typedefs
		typedef boost::shared_ptr< TaskError > Ptr;
};

template < typename Input >
class TaskInput : public Common::Future< Input, TaskError >
{
	public: // typedefs
		typedef boost::shared_ptr< TaskInput > Ptr;
};

class Task
{
	public: // typedefs
		typedef boost::shared_ptr< Task > Ptr;

	private: // attributes
		std::string iName;

	public: // methods
		Task( const std::string &aName )
		{
			std::stringstream ss;

			ss << aName << "<" << (void *)this << ">";

			iName = ss.str();
		}

		virtual ~Task() {};

		const std::string &getName() const { return iName; }

		virtual void operator()() = 0;
};

class TaskScheduler : public Common::AutoSingleton< TaskScheduler >
{
	public:
		TaskScheduler() {};

		void addTask( Task::Ptr &aTask )
		{
			L_ << "Adding task " << aTask->getName() << " to TaskScheduler";

			(*aTask)();
		}
};

// ----------------------------------------------------------------------------

class Object
{
	public: // typedefs
		typedef boost::shared_ptr< Object > Ptr;
		typedef TaskInput< Object > Future; 
	
	public:
		std::string getObject() { return std::string( "Object" ); }
};

class Matrix
{
	public: // typedefs
		typedef boost::shared_ptr< Matrix > Ptr;
		typedef TaskInput< Matrix > Future;
		
	public:
		std::string getMatrix() { return std::string( "Matrix" ); }
};

class RenderSceneTask : public Task
{
	public: // methods
		RenderSceneTask() : Task( "RenderSceneTask" ) {};
		virtual ~RenderSceneTask() {};

		virtual void operator()()
		{

		}
};

class ProcessSceneTask : public Task
{
	public: // methods
		ProcessSceneTask() : Task( "ProcessSceneTask" ) {};
		virtual ~ProcessSceneTask() {};

		virtual void operator()()
		{
			RenderSceneTask::Ptr renderSceneTask = RenderSceneTask::Ptr( new RenderSceneTask() );

			TaskScheduler::getRef().addTask( renderSceneTask );
		}
};

class ProcessObjectTaskInput : public Common::FutureList
{
	public: // typedefs
		typedef boost::shared_ptr< ProcessObjectTaskInput > Ptr;

	public:
		Matrix::Future::Ptr matrix;
		Object::Future::Ptr object;

	public:
		ProcessObjectTaskInput()
		{
			matrix = Matrix::Future::Ptr( new Matrix::Future() );
			object = Object::Future::Ptr( new Object::Future() );

			addFuture( matrix );
			addFuture( object );
		}
};

class ProcessObjectTask : public Task
{
	public:
		ProcessObjectTaskInput::Ptr iInput;

	public:
		ProcessObjectTask( ProcessObjectTaskInput::Ptr &aInput ) : Task( "ProcessObjectTask" )
		{
			iInput = aInput;
		}

		virtual void operator()()
		{
			//L_ << iInput->matrix->getValue()->getMatrix() << " " << iInput->object->getValue()->getObject();
		}
};

int main( int /* argc */, char ** /* argv */ )
{
	Common::Logger::initialize();

	ProcessSceneTask::Ptr processSceneTask = ProcessSceneTask::Ptr( new ProcessSceneTask() );

	TaskScheduler::getRef().addTask( processSceneTask );
	
	return 0;
}
